
package io;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jdom2.Element;
import org.jdom2.JDOMException;

import ui.MainPage;
import users.Role;

/**
 * This class provides access to UserHasConfRole data for the peer review
 * system.
 * 
 * @author Lun-Wei Chang
 * @author Christopher M. Augg
 * @author James Kantak
 * @author Aaron Chen
 * 
 * @version March 9, 2014
 * 
 */
public class UserHasConfRoleAccess extends AbstractAccess {

  /** The USERCONFROLE ID.*/
  public static final int USERCONFROLE_ID = 0;
  /** The user id. */
  public static final int USER_ID = 1;
  /** The conference id. */
  public static final int CONF_ID = 2;
  /** The role id. */
  public static final int ROLE_ID = 3;

  /** The name of the XML file. */
  private static final String XML_FILE = "UserHasConfRole.xml";

  /**
   * A constant for the UserHasConfRole identification attribute in the XML
   * file.
   */
  private static final String NODE_USERCONFROLE_ID = "USerConfRoleID";

  /** A constant for the USER ID attribute in the XML file. */
  private static final String NODE_USER_ID = "UserID";

  /** A constant for the CONFERENCE ID attribute in the XML file. */
  private static final String NODE_CONF_ID = "ConfID";

  /** A constant for the ROLE ID attribute in the XML file. */
  private static final String NODE_ROLE_ID = "RoleID";
  
  

  /**
   * The constructor to instantiate the UserHasConfHasMan objects.
   * 
   * @throws IOException If there is a problem establishing connectivity to the
   *           file.
   * @throws JDOMException If the file cannot be correctly parsed.
   */
  public UserHasConfRoleAccess() throws IOException, JDOMException {
    super(XML_FILE);
  }

  /**
   * This method gets all of the roles associated by a user in a particular
   * conference.
   * 
   * @param the_confid The id that represents the conference the user is
   *          associated with.
   * @param the_userid The id that represent which user is associated with the
   *          conference.
   * 
   * @return A list of role id's for the user.
   */
  public List<Long> getRoleIDs(final long the_confid, final long the_userid) {

    /** An array list to map the user's manuscripts. */
    final List<Long> roleids = new ArrayList<Long>();

    final Element rootnode = getDoc().getRootElement();
    final List<Element> list = rootnode.getChildren();

    for (int i = 0; i < list.size(); i++) {

      final Element node = (Element) list.get(i);

      if (Long.parseLong(node.getChildText(NODE_USER_ID)) == the_userid
          && Long.parseLong(node.getChildText(NODE_CONF_ID)) == the_confid) {

        final String str = node.getAttributeValue("id");
        final long num = Long.parseLong(str);

        roleids.add(num);

      }
    }
    return roleids;

  }
  /**
   * This method returns a list of ConfRoleID objects that provide the conference id and
   * role id associated with the user id passed in as an argument.
   * 
   * @param the_userid the User's id.
   * @return The ConfRoleID object with the user's conference id and role id.
   */
  public List<ConfRoleID> getConfRoles(final Long the_userid) {

    /** An array list to map the user's conferences. */
    final List<ConfRoleID> confroles = new ArrayList<ConfRoleID>();

    final Element rootnode = getDoc().getRootElement();
    final List<Element> list = rootnode.getChildren(NODE_USERCONFROLE_ID);

    for (int i = 0; i < list.size(); i++) {

      final Element node = (Element) list.get(i);

      if (Long.parseLong(node.getChildText(NODE_USER_ID)) == the_userid) {

        final String str1 = node.getChildText(NODE_CONF_ID);
        final String str2 = node.getChildText(NODE_ROLE_ID);
        final Long conf = Long.parseLong(str1);
        final Long role = Long.parseLong(str2);
        final ConfRoleID cr = new ConfRoleID(conf, role);
        confroles.add(cr);

      }
    }
    return confroles;

  }
  
  /**
   * This object writes the conf id, user id, and role id for each role the user has
   * into the UserHasConfRole.xml file.
   * 
   * @param the_role the User object passed into the method.
   * 
   * @return true if successful, false otherwise
   */
  public boolean createUserRoles(final Role the_role) {
    boolean result = false;

    final Element rootnode = getDoc().getRootElement();
    final Element new_element = userToRoleData(the_role, false);
    rootnode.addContent(new_element);
    MainPage.getDatabase().accessRole().createRole(the_role);

    // If the write operation has failed, then remove the node so that
    // subsequent write operations do not include this node.
    result = writeToDatabase();
    if (!result) {
      new_element.detach();
    }

    return result;
  }
  
  /**
   * This object writes the conf id, user id, and role id for each role the user has
   * into the UserHasConfRole.xml file.
   * 
   * @param the_role the User object passed into the method.
   * 
   * @return true if successful, false otherwise
   */
  public boolean editUserRoles(final Role the_role) {
    boolean result = false;

    final Element rootnode = getDoc().getRootElement();
    final List<Element> list = rootnode.getChildren();
    Element old_element = null;
    final Element new_element = userToRoleData(the_role, true);
    for (Element e : list) {
      if (Long.parseLong(e.getAttributeValue("id")) == the_role.getID()) {
        old_element = e.detach();
        rootnode.addContent(new_element);
        result = true;
        break;
      }
    }

    // If the write operation has failed, then remove the node so that
    // subsequent write operations do not include this node.
    if (result) {
      result = writeToDatabase();
      if (!result) {
        rootnode.addContent(old_element);
        new_element.detach();
      }
    }

    return result;
  }
  
  /**
   * Helper method for the editUserRoles method.
   * 
   * @param the_role the user object passed into this method.
   * @param the_edit the true or false value.
   * @return The element to be written.
   */
  private Element userToRoleData(final Role the_role, final boolean the_edit) {
    final Element rolenode = new Element(NODE_USERCONFROLE_ID);

    if (!the_edit) {
      final long id = getNextID();
      rolenode.setAttribute("id", Long.toString(id));
      the_role.setID(id);
    } else {
      rolenode.setAttribute("id", Long.toString(the_role.getID()));
    }
    
    rolenode.addContent(new Element(NODE_USER_ID).
                        setText(Long.toString(the_role.getUser().getID())));
    rolenode.addContent(new Element(NODE_CONF_ID).
                        setText(Long.toString(the_role.getConferenceID())));
    rolenode.addContent(new Element(NODE_ROLE_ID).
                        setText(Long.toString(the_role.getRoleID())));
    
    return rolenode;
  }

  /**
   * An inner class object to represent a Conference to role relationship. It is
   * only instantiated when the getConfRoles method is called.
   * 
   * @author Christopher M. Augg
   * 
   * @version March 19, 2014
   * 
   */
  public class ConfRoleID {

    /** Holds the conference ID when instantiated. */
    private Long my_conf_id;

    /** Holds the Role ID when instantiated. */
    private Long my_role_id;

    /**
     * The constructor for instantiating this object.
     * 
     * @param the_conf_id The conference id related to the user.
     * @param the_role_id The role id related to the user.
     */
    public ConfRoleID(final Long the_conf_id, final Long the_role_id) {
      my_conf_id = the_conf_id;
      my_role_id = the_role_id;
    }

    /**
     * A getter method to return the conference id stored in this object.
     * 
     * @return the user's conference id.
     */
    public Long getConfID() {
      return my_conf_id;
    }

    /**
     * A getter method to return the role id stored in this object.
     * 
     * @return the user's role id.
     */
    public Long getRoleID() {
      return my_role_id;
    }
  }
}
